(function(){
	
	phnq.phnqlets =
	{
		phnqtions: {},
		phnqtionIndexes: {},
		
		isPhnqtionLoaded: function(type)
		{
			return typeof(phnq.phnqlets.phnqtionIndexes[type]) != "undefined";
		},
		
		getLoadedPhnqtionMask: function()
		{
			var bits = new phnq.util.Bitset();
			var phnqtions = phnq.phnqlets.phnqtions;
			for(idx in phnqtions)
			{
				bits.set(idx, true);
			}
			return bits.toString();
		},
		
		update: function(callback)
		{
			var unloadedTypes = [];
			var phps = getPhps();
			var len = phps.length;
			if(len)
			{
				for(var i=0; i<len; i++)
				{
					var php = phps[i];
					
					/*
						TODO: might want to detect if the php is "exposed" here
						and ignore it if it is not.
					*/
					
					var type = php.getAttribute("type");
					if(!phnq.runtime.isTemplateLoaded(type) || !phnq.phnqlets.isPhnqtionLoaded(type))
						unloadedTypes.push(type);
				}
			
				var replacePhps = function()
				{
					for(var i=0; i<len; i++)
					{
						var php = phps[i];
						
						var type = php.getAttribute("type");
						var markup = phnq.runtime.getMarkup(type);
						
						var tempDiv = document.createElement("DIV");
						tempDiv.innerHTML = markup;
						var tmpltElmnt = tempDiv.firstChild;
						
						/*	The first class name on the php will always be phnqlet_ph
						*	so, remove that and then add the rest to the tmpltElmnt.
						*/
						var classes = php.className.split(" ");
						classes.splice(0, 1);

						if(classes.length)
							phnq.dom.addClass(tmpltElmnt, classes.join(" "));
						
						var parent = php.parentNode;
						parent.replaceChild(tmpltElmnt, php);
					}
				};
			
				if(unloadedTypes.length)
				{
					var loadOptions =
					{
						types: unloadedTypes.join(","),
						loadedPhnqtions: phnq.phnqlets.getLoadedPhnqtionMask(),
						loadedTmplts: phnq.runtime.getLoadedTmpltMask()
					};
					
					phnq.io.exec("load", loadOptions, function(result)
					{
						phnq.runtime.eval(result.tmplt);
						eval(result.script);
						phnq.util.appendCSS(result.style);
						replacePhps();
						
						// Call update again in case any lazy php's were added.
						phnq.phnqlets.update(callback);
					});
				}
				else
				{
					replacePhps();
					phnq.phnqlets.update(callback);
				}
			}
			else
			{
				/*	When all templates and phnqtions are loaded and rendered
				*	(if required) then the phnqlets can finally be initialized.
				*/
				var elmnts = phnq.dom.getElementsByClassName("phnqlet_ni");
				var i = elmnts.length;
				while(i--)
				{
					var elmnt = elmnts[i];
					phnq.dom.removeClass(elmnt, "phnqlet_ni");
					var t = phnq.dom.getClasses(elmnt)[0];
					var idx = phnq.phnqlets.phnqtionIndexes[t];
					var obj = new phnq.phnqlets.phnqtions[idx]();
					if(obj)
					{
						obj.element = elmnt;
						if(obj.init)
							obj.init();
					}
				}
				
				if(callback)
					callback();
			}
		},
		
		getScriptFooter: function(idx)
		{
			var buf = [];
			buf.push("phnq.phnqlets.phnqtions[");
			buf.push(idx);
			buf.push("]=function(){");
			buf.push("this.init=(typeof(init)=='function'?init:null);");
			buf.push("this.start=(typeof(start)=='function'?start:null);");
			buf.push("this.show=(typeof(show)=='function'?show:null);");
			buf.push("this.hide=(typeof(hide)=='function'?hide:null);");
			buf.push("};");
			return buf.join("");
		}
	};

	var getPhps = function()
	{
		var elmnts = phnq.dom.getElementsByClassName("phnqlet_ph");
		var phps = [];
		var len = elmnts.length;
		for(var i=0; i<len; i++)
		{
			var elmnt = elmnts[i];
			if(elmnt.nodeName == "UL" && phnq.dom.isExposed(elmnt))
				phps.push(elmnt);
		}
		return phps;
	};
	
	phnq.event.listen(window, "load", function()
	{
		// Run phnq.phnqlets.update to render lazy phnqlets.
		phnq.phnqlets.update();
	});
})();
